package ldh.im.fxbase.richtext;

import javafx.scene.input.Clipboard;
import org.fxmisc.richtext.GenericStyledArea;
import org.fxmisc.richtext.StyledTextArea;
import org.fxmisc.richtext.model.Codec;
import org.fxmisc.richtext.model.ReadOnlyStyledDocument;
import org.fxmisc.richtext.model.SegmentOps;
import org.fxmisc.richtext.model.TextOps;
import org.reactfx.util.Either;

import java.util.*;

public class ImTextArea extends GenericStyledArea<Void, Either<String, TextItem>, String> {

    private static final TextOps<String, String> STYLED_TEXT_OPS = SegmentOps.styledTextOps();
    private static final TextItemOps<String> HYPERLINK_OPS = new TextItemOps<>();

    private static final TextOps<Either<String, TextItem>, String> EITHER_OPS = STYLED_TEXT_OPS._or(HYPERLINK_OPS, (s1, s2) -> Optional.empty());

    public ImTextArea() {
        super(
                null,
                (t, p) -> { },
                "",
                EITHER_OPS,
                e -> e.getSegment().unify(
                        text -> StyledTextArea.createStyledTextNode(text, null, (t, style) -> {}),
                        textItem -> textItem.createNode()
                )
        );

        setWrapText(true);
        getStyleClass().add("im-text-area");
        setStyleCodecs(TextItem.createVoidCodec(), Codec.styledSegmentCodec(Codec.eitherCodec(TextItem.createStringCodec(), TextItem.createCodec()), TextItem.createStringCodec()));
    }

    public String getData() {
        String[] array = getParagraphs().stream().map(ps->{
            StringBuilder stringBuilder = new StringBuilder();
            ps.getSegments().forEach(s->{
                if (s.isLeft()) {
                    stringBuilder.append(s.getLeft());
                } else {
                    TextItem textItem = s.getRight();
                    stringBuilder.append(textItem.getImData());
                }
            });
            return stringBuilder.toString();
        }).toArray(n -> new String[n]);
        return String.join("\n", array);
    }

    public void insertImage(String imageUrl) {
        ReadOnlyStyledDocument<Void, Either<String, TextItem>, String> ros =
                ReadOnlyStyledDocument.fromSegment(Either.right(new ImageTextItem(imageUrl)), null, "image", getSegOps());
        replaceSelection(ros);
    }

    public void insertEmoji(String emoji) {
        ReadOnlyStyledDocument<Void, Either<String, TextItem>, String> ros =
                ReadOnlyStyledDocument.fromSegment(Either.right(new EmojiTextItem(emoji)), null, "emoji", getSegOps());
        replaceSelection(ros);
    }

    public void insertString(String str) {
        replaceSelection(str);
    }

    public void insertTextItem(TextItem textItem) {
        if (textItem.getTextItemType() == TextItemType.emoji) {
            insertEmoji(textItem.getData());
        } else if (textItem.getTextItemType() == TextItemType.image) {
            insertImage(textItem.getData());
        }
    }

    public void clear() {
        this.replaceText(0, this.getContent().length(), "");
    }

    public void setImData(String content) {
        String[] strs = content.split(TextItem.SPLIT_STRING2);
        for(String s : strs) {
            if (s.equals("")) continue;
            TextItem textItem = TextItem.parse(s);
            if (textItem == null) {
                insertString(s);
            } else {
                insertTextItem(textItem);
            }
        }
    }

    @Override
    public void paste() {
        Clipboard clipboard = Clipboard.getSystemClipboard();
        try {
            String str = clipboard.getString();
            if (str.startsWith(ImTextPane.COPY_HEADER)) {
                this.setImData(str.substring(ImTextPane.COPY_HEADER.length()));
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.paste();
    }

    public static List<Object> split(String content) {
        List<Object> result = new ArrayList<>();
        String[] strs = content.split(TextItem.SPLIT_STRING2);
        StringBuilder stringBuilder = new StringBuilder();
        for(String s : strs) {
            if (s.equals("")) continue;
            TextItem textItem = TextItem.parse(s);
            if (textItem == null) {
                stringBuilder.append(s);
            } else if (textItem.getTextItemType() == TextItemType.image) {
                result.add(textItem);
            } else {
                stringBuilder.append(textItem.getImData());
            }
        }
        String end = stringBuilder.toString();
        if (!end.equals("")) {
            result.add(end);
        }
        return result;
    }

    public static int richTextType(String content) {
        if (content.indexOf(TextItem.SPLIT_STRING) < 0) {
            return 1;
        }
        String[] strList = content.split(TextItem.SPLIT_STRING2);
        Map<String, Integer> countMap = new HashMap<>();
        int total = 0;
        for(String str : strList) {
            if (str.equals("")) continue;
            total++;
            boolean ishave = false;
            for(TextItemType textItemType : TextItemType.values()) {
                if (str.startsWith(textItemType.name())) {
                    ishave = true;
                    incr(countMap, textItemType.name());
                    break;
                }
            }
            if (!ishave) {
                incr(countMap, "str");
            }
        }
        if (countMap.containsKey("str") && total == countMap.get("str")) return 1; // 字符串
        if (countMap.containsKey(TextItemType.image.name()) && total == countMap.get(TextItemType.image.name()) && total == 1) return 2; // 图片
        return 3;   // richText
    }

    private static void incr(Map<String, Integer> countMap, String key) {
        Integer count = countMap.get(key);
        if (count == null) {
            count = 1;
            countMap.put(key, count);
        } else {
            count++;
            countMap.put(key, count);
        }
    }
}
